计算机网络


一、基础知识

1. 状态码

状态码 说明
200 请求访问成功。
203 请求无资源访问权限。
301 资源被永久转移到其它地址。
404 请求的访问的资源不存在。
500 服务器内部执行错误。

2. 七层模型

名称 描述
应用层 网络服务与最终用户的一个接口。
表示层 数据的表示、安全、压缩,(在五层模型里面已经合并到了应用层)。
会话层 建立、管理、终止会话,(在五层模型里面已经合并到了应用层)。
传输层 定义传输数据的协议端口号,以及流控和差错校验。
网络层 进行逻辑地址寻址,实现不同网络之间的路径选择。
数据链路层 建立逻辑连接、进行硬件地址寻址、差错校验等功能。
物理层 建立、维护、断开物理连接。(由底层网络定义协议)。
(1) 应用层

应用层用于终端用户软件,如 web 浏览器和电子邮件客户端。它提供协议,允许软件发送和接收信息,并向用户呈现有意义的数据。

应用层协议的几个例子是超文本传输协议 (HTTP)、文件传输协议 (FTP)、邮政协议 (POP)、简单邮件传输协议 (SMTP) 和域名系统 (DNS)

(2) 表示层

表示层为应用层准备数据,它定义了两个设备应该如何编码、加密和压缩数据,以便在另一端正确接收数据。表示层接收应用层传输的任何数据,并为在会话层上传输做好准备。

(3) 会话层

会话层在设备之间创建通信通道,称为会话,它负责打开会话,确保它们在传输数据时保持打开和功能,并在通信结束时关闭它们。会话层还可以在数据传输期间设置检查点——如果会话中断,设备可以从上一个检查点恢复数据传输。

(4) 传输层

传输层接收在会话层传输的数据,并在传输端将其分成 ,它负责在接收端重新组装数据段,并将其转换回会话层可以使用的数据。

传输层进行流量控制,以与接收设备的连接速度相匹配的速率发送数据,以及错误控制,检查数据是否被错误接收,如果没有则重新请求数据,常见的协议如 TCP 即处于传输层。

(5) 网络层

网络层主要有两个功能:一种是将数据段分解为网络数据包,然后在接收端重新组装这些数据包;另一种是通过发现穿越物理网络的最佳路径来路由数据包。

网络层使用网络地址(通常是 Internet 协议地址)将数据包路由到目标节点。

(6) 数据链路层

数据链路层在网络上两个物理连接的节点之间建立和终止连接。它将数据包分解成帧,并将其从源发送到目的。

该层由逻辑链路控制 (LLC) 和媒体访问控制 (MAC) 两部分组成,前者负责识别网络协议、执行错误检查和同步帧,后者使用 MAC 地址连接设备并定义传输和接收数据的权限。

(7) 物理层

物理层负责网络节点之间的物理电缆或无线连接。它定义了连接设备的连接器、电缆或无线技术,并负责传输原始数据,这只是一系列 01,同时负责比特率控制。

二、传输协议

1. IP协议

IP 是互联网协议,是一种网络层协议,允许在网络上任何位置的两台主机之间传输数据包(网络可以是私有的、隔离的网络,也可以是 Internet)。

IP 都是关于数据包的,它没有说明包的内容。尽管可以将 IP 数据包发送到网络中的任何其他主机,但基本协议对最终用户来说并没有那么有用,因为除非查看数据包的内容,否则无法区分数据包。因此,还有其他更高级别的协议建立在 IP 之上,允许应用程序更智能地使用网络。

2. TCP协议

TCP 是传输控制协议,在 IP 上运行,所以通用名称为 TCP/IP,它的目的是在两台主机之间建立了通信通道提供可靠的通信流。

TCP 保证消息按照最初发送的顺序传递。此外,TCP 包含处理拥塞的特殊机制,使用特殊算法检测数据包丢失并相应地调整传输速度。

3. UDP协议

UDP 是用户数据报协议,是另一种直接在 IP 上运行的协议。其与 TCP 区别在于 UDP 更简单,并且不提供任何使 TCP 如此有用的特殊保证。

UDP 消息被发送到目的地,没有保证的传递,也没有关于传递顺序的保证,也不提供拥塞控制。另一方面,UDP 更简单高效,这使得它非常适合那些需要非常短的消息交换才能工作的协议(DNS 是一个很好的例子),或者不需要相同的交付保证。

4. HTTP协议

HTTP 是超文本传输协议,是一个应用程序协议,旨在为客户端提供检索和操作超文本对象和组件(包括 HTML 页面、PNG 图像等)的方法。

HTTP 运行在 TCP 之上,而 TCP 又运行在 IP 之上,与 IP (一种网络协议)和 TCP (一种传输协议)相比,HTTP 是一种应用协议——这意味着它被应用程序直接使用。

三、HTTP发展

1. HTTP/0.9

HTTP/0.91991 第一次被提出,是一种无头 (没有请求头),只允许发送 GET 请求且返回值只能是 HTML 内容的请求方式。

假设客户端发出了下述一个简单的请求:

GET /index.html

则上述请求对应的返回响应如下:

(response body)
(connection closed)

2. HTTP/1.0

1996HTTP/1.0 问世,扩展提高了 HTTP/0.9 协议,引入了请求头并新增了 POSTHEAD 接口协议。

不同于 HTTP/0.91.0 中允许了多种数据返回内容,此时不再只运行返回 HTML 内容,还可返回图片、文件、视频等等。

如下为一个简易的 1.0 协议请求示例:

GET / HTTP/1.0
Host: cs.fyi
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*

上述请求对应的响应体格式则如下,可以看到不仅有了请求头,还多了现今人们熟悉的状态码如 200。也正是引入了请求头,即可通过 Content-Type 控制返回的数据内容格式,使其不再局限于 0.9 中的 HTML 内容格式。

HTTP/1.0 200 OK 
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84

(response body)
(connection closed)

3. HTTP/1.1

仅在三年后的 1999HTTP/1.1 即正式发布,引入了下述新特性:

  • 新增了 PUT, PATCH, OPTIONS, DELETE 请求方式。
  • 1.0 中请求头并非必选项,但在 1.1 中任意请求或响应都需包含请求头。
  • 1.0 中支持了长连接从而大大提高的服务请求效率。
  • 引入了管道 (Pipelining) 实现了并发请求而无需阻塞等待请求响应。

除了上述几类,同时还涵括了缓存 (Caching)、编码 (Character sets) 以及新的状态码 (status codes) 等等特性,此处不一一列出。

HTTP/1.1 中的一大核心改变即长连接的提出,在此前的协议中,请求与响应都是一次性,意味着每当客户端需要请求服务端其都需要创建一个新的连接完成后再关闭。而由于三次握手的存在,重复的连接创建关闭将会大大降低传输的效率,因此长连接的引入极大提高了传输效率。

4. HTTP/2.0

HTTP/1.1 持续应用了相当长的一段时间后,2015HTTP/2.0 才被提出并沿用至今。

2.0 中针对传输的内容提出进一步的优化,此时传输的内容转为 byte 数据传输,同时将数据压缩为一个或多个帧 (Frame),每一个帧即 byte 块,而多个帧组合即成为流 (Stream),提高了效率但也导致了数据人眼不可读。同时在 2.0 中针对请求与响应的请求头进行压缩进一步提高效率和降低延迟。

四、消息通信

1. 三次握手

客户端和服务端通信前要进行连接,3次握手 的作用就是双方都能明确自己和对方的收、发能力是正常的。

(1) 第一次握手

客户端发送一个 SYN 段,其包含一个随机数 ISN(c),指明客户端的初始序列号。

(2) 第二次握手

服务端收到客户端的 SYN 段后,发送自己的 SYN 段作为应答,同样指明自己的 ISN(c),为了确认客户端的 SYN,将客户端发送的 ISN(c) + 1 作为 ACK 数值。这样每发送一个 SYN 序列号就加 1,如果丢失则会重传。

(3) 第三次握手

为了确认服务器端的 SYN ,客户端将 ISN(s)+1 作为返回的 ACK 数值。

2. 四次挥手

挥手之前主动释放连接的客户端结束 ESTABLISHED 阶段,随后开始 四次挥手

(1) 第一次挥手

首先客户端想要释放连接,向服务器端发送一段 TCP 报文,其中:

  • 标记位为 FIN,表示请求释放连接;
  • 序号为 Seq=U
  • 随后客户端进入 FIN-WAIT-1 阶段,即半关闭阶段,并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。

注意:这里不发送的是正常连接时传输的数据(非确认报文),而不是一切数据,所以客户端仍然能发送 ACK 确认报文。

(2) 第二次挥手

服务器端接收到从客户端发出的 TCP 报文之后,确认了客户端想要释放连接,随后服务器端结束 ESTABLISHED 阶段,进入 CLOSE-WAIT 阶段(半关闭状态)并返回一段 TCP 报文,其中:

  • 标记位为 ACK ,表示接收到客户端发送的释放连接的请求;
  • 序号为 Seq=V
  • 确认号为 Ack=U+1 ,表示是在收到客户端报文的基础上,将其序号 Seq+1 作为本段报文确认号 Ack 的值;随后服务器端开始准备释放服务器端到客户端方向上的连接。
  • 客户端收到从服务器端发出的 TCP 报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束 FIN-WAIT-1 阶段,进入 FIN-WAIT-2 阶段

前两次挥手既让服务器端知道客户端想要释放连接,也让客户端知道服务器端了解自己想要释放连接的请求。

(3) 第三次挥手

服务器端自从发出 ACK 确认报文之后,经过 CLOSED-WAIT 阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段 TCP 报文,其中:

  • 标记位为 FIN ,ACK,表示已经准备好释放连接了。注意:这里的 ACK 并不是确认收到服务器端报文的确认报文。
  • 序号为 Seq=W
  • 确认号为 Ack=U+1;表示是在收到客户端报文的基础上,将其序号 Seq + 1 作为本段报文确认号 Ack 的值。
  • 随后服务器端结束 CLOSE-WAIT 阶段,进入 LAST-ACK 阶段。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。
(4) 第四次挥手

客户端收到从服务器端发出的 TCP 报文,确认了服务器端已做好释放连接的准备,结束 FIN-WAIT-2 阶段,进入 TIME-WAIT 阶段,并向服务器端发送一段报文,其中:

  • 标记位为 ACK ,表示接收到服务器准备好释放连接的信号。
  • 序号为 Seq=U+1 ;表示是在收到了服务器端报文的基础上,将其确认号 Ack 值作为本段报文序号的值。
  • 确认号为 Ack=W+1 ;表示是在收到了服务器端报文的基础上,将其序号 Seq 值作为本段报文确认号的值。
  • 随后客户端开始在 TIME-WAIT 阶段等待 2MSL

3. 网络粘包

TCP 传输中会涉及到一个概念 —— 网络粘包,但其并非真正意义上 TCP 层的问题。

首先我们需要了解什么是粘包,在上面提到了 TCP 是传输层协议,以流的形式即负责数据的传输。而为了取得更高的传输性能,通常会采用 Nagle 算法将多个数据包合并后执行发送,从而减少网络传输的次数以提高效率。但合并操作也就带来一个问题,发送端本应是多条消息由于合并为单条导致接收方收到的数据包是也就只有单条。

举个简单示例,客户端发送了 2 条消息,由于 Nagle 算法的存在数据包被合并为了一条,此时服务端本应该接受 2 条信息但却只接收到一条。若服务端没有针对接受的数据包执行重新拆包处理,那么服务端将无法正确处理接收到的数据包,这个过程也是就粘包。

那为什么又称粘包并非 TCP 问题,正是因为上述提到的 TCP 为传输层协议,只负责数据流的点对点传输。对于传输层而言,其只负责数据的完整传输送达,而粘包问题应在应用层执行拆包解决而非由 TCP 协议处理。

如果接收端没有单独的拆包处理,又想避免粘包问题的出现,可以在发送端配置开启 TCP_NODELAY 从而禁用 Nagle 算法,如在 Netty 中即可通过 option(ChannelOption.TCP_NODELAY, true) 禁用 Nagle

public void init() {
    Bootstrap bootstrap = new Bootstrap()
            // 禁用 Nagle 算法,发送数据包时都会立即发送,不会等待数据包的合并发送。
            .option(ChannelOption.TCP_NODELAY, true)
            .handler(new SimpleClientInitializer());
}

参考链接

  1. OSI Model
  2. How does the Internet Work?
  3. Everything you need to know about HTTP

文章作者: 烽火戏诸诸诸侯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
  目录